/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_components/zhiqim_manager.htm
 *
 * Zhiqim Manager is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.manager.action;

import java.sql.Timestamp;
import java.util.List;
import java.util.Random;

import org.zhiqim.httpd.HttpRequest;
import org.zhiqim.httpd.context.ZmlBootstrap;
import org.zhiqim.httpd.context.core.Context;
import org.zhiqim.httpd.context.extend.StdSwitchAction;
import org.zhiqim.httpd.validate.ones.IsNotEmpty;
import org.zhiqim.httpd.validate.onex.IsEmail;
import org.zhiqim.httpd.validate.onex.IsIP;
import org.zhiqim.httpd.validate.onex.IsMobile11;
import org.zhiqim.httpd.validate.onex.IsUserCode;
import org.zhiqim.httpd.validate.onex.IsUserPass;
import org.zhiqim.kernel.annotation.AnTransaction;
import org.zhiqim.kernel.json.Jsons;
import org.zhiqim.kernel.model.maps.LinkedMapSO;
import org.zhiqim.kernel.model.maps.MapSO;
import org.zhiqim.kernel.model.results.R1;
import org.zhiqim.kernel.paging.PageResult;
import org.zhiqim.kernel.util.Arrays;
import org.zhiqim.kernel.util.Randoms;
import org.zhiqim.kernel.util.Sqls;
import org.zhiqim.kernel.util.Validates;
import org.zhiqim.manager.ZmrBootstrap;
import org.zhiqim.manager.ZmrConstants;
import org.zhiqim.manager.ZmrPassworder;
import org.zhiqim.manager.dao.ZmrDeptDao;
import org.zhiqim.manager.dao.ZmrOperatorDao;
import org.zhiqim.manager.dbo.ZmrAvatar;
import org.zhiqim.manager.dbo.ZmrDept;
import org.zhiqim.manager.dbo.ZmrOperator;
import org.zhiqim.manager.dbo.ZmrOperatorLog;
import org.zhiqim.manager.dbo.ZmrOperatorRule;
import org.zhiqim.manager.dbo.ZmrParamOperator;
import org.zhiqim.manager.dbo.ZmrRole;
import org.zhiqim.orm.ORM;
import org.zhiqim.orm.dbo.Selector;
import org.zhiqim.orm.dbo.Updater;

/**
 * 操作员/管理员管理
 *
 * @version v1.0.0 @author zouzhigang 2015-5-28 新建与整理
 */
public class OperatorAction extends StdSwitchAction implements ZmrConstants
{
    protected void validateId(HttpRequest request)
    {
        request.addValidate(new IsUserCode("operatorCode","操作员账号由2-16位字母数字汉字开头，字母汉字数字特殊符号组成"));
    }
    
    protected void validateForm(HttpRequest request)
    {
        request.addValidate(new IsUserCode("operatorCode","操作员账号由2-16位字母数字汉字开头，字母汉字数字特殊符号组成"));
        request.addValidate(new IsNotEmpty("operatorName", "操作员名称不能为空"));
        request.addValidate(new IsNotEmpty("operatorValid", "操作员状态不能为空"));
        request.addValidate(new IsIP("operatorIp", "请输入正确的IP地址", true));
        request.addValidate(new IsMobile11("operatorMobile", "请输入正确的手机号", true));
        request.addValidate(new IsEmail("operatorEmail", "请输入正确的邮箱", true));
    }

    protected void list(HttpRequest request) throws Exception
    {
        int page = request.getParameterInt(_PAGE_, 1);
        int pageSize = request.getContextAttributeInt(ZMR_PAGE_SIZE, 20);
        
        List<ZmrDept> deptList = ZmrDeptDao.list();
        List<ZmrRole> roleList = ORM.table().list(ZmrRole.class);
        
        Selector selector = new Selector().addMustThenG("operatorType", 0);
        //状态
        selector.addMaybe("operatorValid", request.getParameterBool("operatorValid"));
        String operatorKey = request.getParameter("operatorKey");
        if (Validates.isNotEmpty(operatorKey))
        {//条件
            selector.addOr(new Selector().addMaybeLike("operatorCode", operatorKey).addMaybeLike("operatorName", operatorKey));
        }
        selector.addOrderbyDesc("operatorValid");
        selector.addOrderbyAsc("operatorType");
        selector.addOrderbyAsc("operatorCreated");
        
        PageResult<ZmrOperator> result = ORM.table().page(ZmrOperator.class, page, pageSize, selector);
        result.addConditionMap(request.getParameterMap());
        
        for (ZmrOperator operator : result.list())
        {
            toDeptName(deptList, operator);
            toRoleName(roleList, operator);
        }
        
        request.setAttribute("result", result);
    }
    
    protected void add(HttpRequest request) throws Exception
    {
        request.addValidate(new IsUserPass("operatorPass", "操作员密码不合法，要求6-16位（大小写字母数字和特殊字符必须四选三）"));
    }

    protected void insert(HttpRequest request) throws Exception
    {
        String operatorCode = request.getParameter("operatorCode");
        String operatorPass = request.getParameter("operatorPass");
        boolean operatorValid = request.getParameterBoolean("operatorValid");
        int operatorType = request.getParameterInt("operatorType", 2);//默认为操作员
        String operatorName = request.getParameter("operatorName");
        String operatorIp = request.getParameter("operatorIp");
        String operatorMobile = request.getParameter("operatorMobile");
        String operatorEmail = request.getParameter("operatorEmail");
        
        if(ORM.table().count(ZmrOperator.class, operatorCode) > 0)
        {
            request.returnHistory("该操作员账号已经存在，请重新输入");
            return;
        }
        
        if(!Validates.isUserPass(operatorPass))
        {
            request.returnHistory("请输入6-16位操作员密码（大小写字母数字和特殊字符必须四选三）");
            return;
        }
        
        long operatorAvatar = 0;
        PageResult<ZmrAvatar> result = ORM.table().page(ZmrAvatar.class, 1, 10, new Selector("avatarId", "avatarType", 0));
        if(result.size() > 0)
        {//随机取一个系统头像
            int ind = new Random().nextInt(result.size());
            operatorAvatar = result.list().get(ind).getAvatarId();
        }
        
        ZmrPassworder passworder = ZmrBootstrap.getPassworder();
        String operatorPassSalt = Randoms.lettersDigitsSecure(64);
        operatorPass = passworder.encode(operatorCode, operatorPass, operatorPassSalt);
        Timestamp timestamp = Sqls.nowTimestamp();
        
        ZmrOperator operator = new ZmrOperator();
        operator.setOperatorCode(operatorCode);
        operator.setOperatorPass(operatorPass);
        operator.setOperatorPassSalt(operatorPassSalt);
        operator.setOperatorValid(operatorValid);
        operator.setOperatorType(operatorType);
        operator.setOperatorName(operatorName);
        operator.setOperatorIp(operatorIp);
        operator.setOperatorAvatar(operatorAvatar);
        operator.setOperatorMobile(operatorMobile);
        operator.setOperatorEmail(operatorEmail);
        operator.setOperatorCreated(timestamp);
        operator.setOperatorModified(timestamp);
        ORM.table().insert(operator);
        
        //增加操作日志
        MapSO map = new LinkedMapSO();
        map.put("operatorCode", operatorCode);
        map.put("operatorName", operatorName);
        map.put("operatorType", operatorType);
        map.put("operatorValid", operatorValid);
        map.put("operatorAvatar", operatorAvatar);
        map.put("operatorMobile", operatorMobile);
        map.put("operatorEmail", operatorEmail);
        map.put("operatorIp", operatorIp);
        
        ZmrOperatorDao.addOperateLog(request, "增加操作员", Jsons.toString(map));
    }

    protected void modify(HttpRequest request) throws Exception
    {
        request.addValidate(new IsUserPass("operatorPass", "操作员密码不合法，要求6-16位（大小写字母数字和特殊字符必须四选三）", true));
        String operatorCode = request.getParameter("operatorCode"); 
        
        ZmrOperator operator = ORM.table().item(ZmrOperator.class, operatorCode);
        if(operator == null)
        {
            request.returnHistory("该操作员不存在，请重新选择");
            return;
        }
        
        List<ZmrParamOperator> operatorParamList = ORM.table().list(ZmrParamOperator.class);
        
        request.setAttribute("operator", operator);
        request.setAttribute("operatorParamList", operatorParamList);
    }
    
    protected void update(HttpRequest request) throws Exception
    {
        String operatorCode = request.getParameter("operatorCode");
        String operatorName = request.getParameter("operatorName");
        String operatorPass = request.getParameter("operatorPass");
        String operatorIp = request.getParameter("operatorIp");
        String operatorMobile = request.getParameter("operatorMobile");
        String operatorEmail = request.getParameter("operatorEmail");
        boolean operatorValid = request.getParameterBoolean("operatorValid");
        int operatorType = request.getParameterInt("operatorType");
        
        boolean hasUpdatePassword = false;
        
        Updater updater = new Updater();
        updater.addMust("operatorCode", operatorCode);
        updater.addField("operatorName", operatorName);
        if(Validates.isNotEmpty(operatorPass))
        {
            if(!Validates.isUserPass(operatorPass))
            {
                request.returnHistory("请输入6-16位操作员密码（大小写字母数字和特殊字符必须四选三）");
                return;
            }
            
            ZmrPassworder passworder = ZmrBootstrap.getPassworder();
            String operatorPassSalt = Randoms.lettersDigitsSecure(64);
            
            operatorPass = passworder.encode(operatorCode, operatorPass, operatorPassSalt);
            updater.addField("operatorPass", operatorPass);
            updater.addField("operatorPassSalt", operatorPassSalt);
            
            hasUpdatePassword = true;
        }
        
        updater.addField("operatorValid", operatorValid);
        updater.addField("operatorIp", operatorIp);
        updater.addField("operatorMobile", operatorMobile);
        updater.addField("operatorEmail", operatorEmail);
        updater.addField("operatorModified", Sqls.nowTimestamp());
        updater.addField("operatorType", operatorType);
        
        ORM.table().update(ZmrOperator.class, updater);
        
        //增加操作日志
        if (hasUpdatePassword)
            ZmrOperatorDao.addOperateLog(request, "修改操作员密码", Jsons.toString("operatorCode", operatorCode));
        else
            ZmrOperatorDao.addOperateLog(request, "修改操作员信息", Jsons.toString("operatorCode", operatorCode));
    }

    public void item(HttpRequest request) throws Exception
    {
        String operatorCode = request.getParameter("operatorCode");
        ZmrOperator operator = ORM.table().item(ZmrOperator.class, operatorCode);
        if (operator == null)
        {
            request.setResponseError("请选择一个有效的操作员");
            return;
        }
        
        String paramKey = request.getParameter("paramKey");
        
        Updater updater = new Updater();
        updater.addMust("operatorCode", operatorCode);
        updater.addField("operatorModified", Sqls.nowTimestamp());
        String operateFeature = null, operateDesc = null;
        if ("operatorPass".equals(paramKey))
        {
            String password = request.getParameter("paramValue");
            if(!Validates.isUserPass(password))
            {
                request.setResponseError("请输入6-16位操作员密码（大小写字母数字和特殊字符必须四选三）");
                return;
            }
            
            ZmrPassworder passworder = ZmrBootstrap.getPassworder();
            String operatorPassSalt = Randoms.lettersDigitsSecure(64);
            
            String operatorPass = passworder.encode(operatorCode, password, operatorPassSalt);
            updater.addField("operatorPass", operatorPass);
            updater.addField("operatorPassSalt", operatorPassSalt);
            
            operateFeature = "修改操作员密码";
            operateDesc = Jsons.toString("operatorCode", operatorCode);
        }
        if ("operatorName".equals(paramKey))
        {
            String operatorName = request.getParameter("paramValue");
            if(!Validates.isLen(operatorName, 1, 64))
            {
                request.setResponseError("操作员名称不能为空，最长64字符");
                return;
            }
            
            updater.addField("operatorName", operatorName);
            operateFeature = "修改操作员名称";
            operateDesc = Jsons.toString("operatorCode", operatorCode, "operatorName", operatorName);
        }
        else if ("operatorType".equals(paramKey))
        {
            int operatorType = operator.getOperatorType()==1?2:1;
            updater.addField("operatorType", operatorType);
            operateFeature = "修改操作员类型";
            operateDesc = Jsons.toString("operatorCode", operatorCode, "operatorType", operatorType);
        }
        else if ("operatorValid".equals(paramKey))
        {
            boolean operatorValid = !operator.isOperatorValid();
            updater.addField("operatorValid", operatorValid);
            operateFeature = "修改操作员状态";
            operateDesc = Jsons.toString("operatorCode", operatorCode, "operatorValid", operatorValid);
        }
        else if ("operatorIp".equals(paramKey))
        {
            String operatorIp = request.getParameter("paramValue");
            if (!Validates.isIP(operatorIp, true))
            {
                request.setResponseError("请输入正确的操作员IP，为空表示不限制");
                return;
            }
            
            updater.addField("operatorIp", operatorIp);
            operateFeature = "修改操作员IP";
            operateDesc = Jsons.toString("operatorCode", operatorCode, "operatorIp", operatorIp);
        }
        else if ("operatorMobile".equals(paramKey))
        {
            String operatorMobile = request.getParameter("paramValue");
            if (!Validates.isMobile11(operatorMobile, true))
            {
                request.setResponseError("请输入正确的操作员手机号，为空表示清除原手机号");
                return;
            }
            
            updater.addField("operatorMobile", operatorMobile);
            operateFeature = "修改操作员手机号";
            operateDesc = Jsons.toString("operatorCode", operatorCode, "operatorMobile", operatorMobile);
        }
        else if ("operatorEmail".equals(paramKey))
        {
            String operatorEmail = request.getParameter("paramValue");
            if (!Validates.isEmail(operatorEmail, true))
            {
                request.setResponseError("请输入正确的操作员邮箱，为空表示清除原邮箱");
                return;
            }
            
            updater.addField("operatorEmail", operatorEmail);
            operateFeature = "修改操作员邮箱";
            operateDesc = Jsons.toString("operatorCode", operatorCode, "operatorEmail", operatorEmail);
        }
        
        if (operateFeature == null)
        {
            request.setResponseError("请选择一个操作员属性进行修改");
            return;
        }
        
        //更新用户属性
        ORM.table().update(ZmrOperator.class, updater);
        
        //增加操作日志
        ZmrOperatorDao.addOperateLog(request, operateFeature, operateDesc);
    }
    
    @AnTransaction
    protected void delete(HttpRequest request) throws Exception
    {
        String operatorCode = request.getParameter("operatorCode");
        ZmrOperator operator = ORM.table().item(ZmrOperator.class, operatorCode);
        if (operator == null)
        {
            request.returnHistory("该操作员不存在");
            return;
        }
        
        Context context = (Context)request.getContext();
        ZmlBootstrap bootstrap = context.getBootstrap();
        R1 result = bootstrap.event(request, ZMR_EVENT_OPERATOR_DELETE_CHK, operatorCode);
        if (result.failure())
        {
            request.returnHistory(result.error());
            return;
        }
        
        ZmrAvatar avatar = ORM.table().item(ZmrAvatar.class, operator.getOperatorAvatar());
        if (avatar != null && avatar.getAvatarType() == 1)
        {//删除操作员头像
            ORM.table().delete(ZmrAvatar.class, operator.getOperatorAvatar());
        }
        
        //删除操作员&权限
        Selector selector = new Selector("operatorCode", operatorCode);
        ORM.table().delete(ZmrOperator.class, operatorCode);
        ORM.table().delete(ZmrOperatorLog.class, selector);
        ORM.table().delete(ZmrOperatorRule.class, selector);
        
        bootstrap.event(request, ZMR_EVENT_OPERATOR_DELETED, operatorCode);
        
        //增加操作日志
        ZmrOperatorDao.addOperateLog(request, "删除操作员", Jsons.toString("operatorCode", operatorCode));
    }
    
    /********************************************************************************************/
    //私有方法
    /********************************************************************************************/
    
    /** 用密码字段填充角色列表 */
    private void toRoleName(List<ZmrRole> roleList, ZmrOperator operator)
    {
        operator.setOperatorPass("");
        
        long[] roleIds = Arrays.toLongArray(operator.getOperatorRole());
        for (long roleId : roleIds)
        {
            for (ZmrRole role : roleList)
            {
                if (role.getRoleId() == roleId)
                {
                    if (Validates.isEmpty(operator.getOperatorPass()))
                        operator.setOperatorPass(role.getRoleName());
                    else
                        operator.setOperatorPass(operator.getOperatorPass() + "," + role.getRoleName());
                    break;
                }
            }
        }
    }
    
    /** 用密码加盐字段填充部门列表 */
    private void toDeptName(List<ZmrDept> deptList, ZmrOperator operator)
    {
        operator.setOperatorPassSalt("");
        
        long[] deptIds = Arrays.toLongArray(operator.getOperatorDept());
        for (long deptId : deptIds)
        {
            for (ZmrDept dept : deptList)
            {
                if (dept.getDeptId() == deptId)
                {
                    if (Validates.isEmpty(operator.getOperatorPassSalt()))
                        operator.setOperatorPassSalt(dept.getDeptName());
                    else
                        operator.setOperatorPassSalt(operator.getOperatorPassSalt() + "," + dept.getDeptName());
                    break;
                }
            }
        }
    }
}
